/*
 * Selector CLASS TEMPLATE:
 * This class presents idiom of "non-linear-access iterator". It is presumed
 * to proxify access through storage of "plain" iterators. Container is presumed
 * to be compatible with BIDIRECTIONAL iterators at least;
 *
 */

#ifndef UNITRAF_GRAPHTRAITS_SELECTOR_HPP
#define UNITRAF_GRAPHTRAITS_SELECTOR_HPP

#include <graph\traits\Traits.hpp>

namespace unitraf {

namespace graph_traits {

// Making aliases
using std::iterator_traits;
using std::shared_ptr;


// See comment at the top of the file
template<class _BaseCont, class _ValTy> 
  class Selector {

    typedef Selector _myt;

    typedef _BaseCont container_type;
    
   public:
    ///////////////////////////////////////////////////////////////////////////
    // PUBLIC INTERFACE

    typedef typename container_type::iterator iterator;

    typedef _ValTy  value_type;
    typedef _ValTy& reference;
    typedef _ValTy* pointer;

    // CONSTRUCTORS AND INITIALIZER
    
    Selector() {};

    // DESTRUCTOR

    ~Selector() {};

    // OPERATORS

    // Check for validity 
    operator bool() { return storage_ ? proxy_ != storage_->end() : 0; };

    _myt& operator++() { ++proxy_; return *this; };

    _myt operator++(int) { _myt copy = *this; ++proxy_; return copy; };

    _myt& operator--() { --proxy_; return *this; };

    _myt operator--() { _myt copy = *this; --proxy_; return copy; };

    reference operator*() { return **proxy_; };

    pointer operator->() { return &(**proxy_); };
      
    // METHODS

    // Add iterator to the selector storage (uses COPY semantic)
    void push_back(const iterator& i) {
      
      if (!storage_) _init();

      storage_->push_back(i);

    };

    // Add iterator to the selector storage (uses MOVE semantic)
    void push_back(iterator&& i) {
      
      if (!storage_) _init();

      storage_->push_back(i);

    };

    // Reset the proxy value
    void reset() { proxy = storage_->begin(); };

    // Check whether the storage is empty
    bool empty() { return storage_; };


   private:
    ///////////////////////////////////////////////////////////////////////////
    // PRIVATE INTERFACE

    typedef list<iterator> storage_type;

    void _init() { storage_ = new container_type(); reset(); };

    // REPRESENTATION

    storage_type storage_;

    typename storage_type::iterator proxy_;

  };

};  // namespace graph_traits

};  // namespace unitraf

#endif  // #ifndef UNITRAF_GRAPHTRAITS_SELECTOR_HPP